Refactor extension build process to use modular build steps#6867
Refactor extension build process to use modular build steps#6867alfonso-noriega wants to merge 1 commit into01-build-steps-infrastructurefrom
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
64d581f to
c4c3353
Compare
1c5c718 to
3ac919f
Compare
c4c3353 to
d2a2b21
Compare
2b6f7ba to
68c2a9f
Compare
d2a2b21 to
3837d71
Compare
8096aa6 to
f6ae0a0
Compare
794d3e0 to
75deab1
Compare
f6ae0a0 to
1b503e0
Compare
75deab1 to
feab6d2
Compare
1b503e0 to
01cfc8b
Compare
feab6d2 to
27b8cfc
Compare
01cfc8b to
048e70a
Compare
27b8cfc to
34005f5
Compare
048e70a to
c25acc0
Compare
4dd6917 to
56f0d4a
Compare
Coverage report
Test suite run success3851 tests passing in 1492 suites. Report generated by 🧪jest coverage report action from 61f4d35 |
| identifier: HostedAppHomeSpecIdentifier, | ||
| buildConfig: {mode: 'hosted_app_home'} as const, | ||
| buildConfig: {mode: 'none'} as const, | ||
| schema: HostedAppHomeSchema, |
There was a problem hiding this comment.
Hosted app home build is effectively disabled (behavior change)
The PR changes hosted_app_home from buildConfig: {mode: 'hosted_app_home'} to {mode: 'none'}. Previously, ExtensionInstance.build() had a hosted_app_home branch that called copyStaticAssets(). After this refactor, mode: 'none' produces steps = [], so no build-time actions happen for hosted app home extensions.
Evidence (new behavior):
ExtensionInstance.build()now does:const steps = buildConfig.mode === 'none' ? [] : buildConfig.stepsand runs only those steps.HostedAppHomespec now setsmode: 'none', so nothing runs.
Impact: Hosted app home extensions can ship without static assets being copied into the build output. End users (merchants) could see missing UI/resources; deployments may succeed but produce broken runtime behavior. This affects all users of that extension type.
|
🤖 Code Review · #projects-dev-ai for questions ✅ Complete - No issues 📋 History✅ 1 findings → ✅ 1 findings → ✅ 2 findings → ✅ No issues |
ef0c29e to
644b571
Compare
61f4d35 to
8b922b5
Compare
Differences in type declarationsWe detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:
New type declarationsWe found no new type declarations in this PR Existing type declarationspackages/cli-kit/dist/private/node/conf-store.d.ts@@ -21,8 +21,6 @@ interface Cache {
export interface ConfSchema {
sessionStore: string;
currentSessionId?: string;
- devSessionStore?: string;
- currentDevSessionId?: string;
cache?: Cache;
}
/**
packages/cli-kit/dist/private/node/testing/ui.d.ts@@ -73,8 +73,7 @@ export declare function sendInputAndWait(renderInstance: ReturnType<typeof rende
export declare function sendInputAndWaitForContent(renderInstance: ReturnType<typeof render>, content: string, ...inputs: string[]): Promise<void>;
/** Function that is useful when you want to check the last frame of a component that unmounted.
*
- * With Ink 6 / React 19, the output is no longer cleared on unmount,
- * so lastFrame() consistently returns the last rendered content.
+ * The reason this function exists is that in CI Ink will clear the last frame on unmount.
*/
export declare function getLastFrameAfterUnmount(renderInstance: ReturnType<typeof render>): string | undefined;
type TrackedPromise<T> = Promise<T> & {
packages/cli-kit/dist/private/node/ui/components/SelectInput.d.ts@@ -1,5 +1,8 @@
import React from 'react';
import { DOMElement } from 'ink';
+declare module 'react' {
+ function forwardRef<T, TProps>(render: (props: TProps, ref: React.Ref<T>) => React.ReactElement | null): (props: TProps & React.RefAttributes<T>) => React.ReactElement | null;
+}
export interface SelectInputProps<T> {
items: Item<T>[];
initialItems?: Item<T>[];
@@ -15,8 +18,7 @@ export interface SelectInputProps<T> {
morePagesMessage?: string;
availableLines?: number;
onSubmit?: (item: Item<T>) => void;
- inputFixedAreaRef?: React.Ref<DOMElement>;
- ref?: React.Ref<DOMElement>;
+ inputFixedAreaRef?: React.RefObject<DOMElement>;
groupOrder?: string[];
}
export interface Item<T> {
@@ -27,5 +29,4 @@ export interface Item<T> {
helperText?: string;
disabled?: boolean;
}
-declare function SelectInput<T>({ items: rawItems, initialItems, onChange, enableShortcuts, focus, emptyMessage, defaultValue, highlightedTerm, loading, errorMessage, hasMorePages, morePagesMessage, availableLines, onSubmit, inputFixedAreaRef, ref, groupOrder, }: SelectInputProps<T>): React.ReactElement | null;
-export { SelectInput };
\ No newline at end of file
+export declare const SelectInput: <T>(props: SelectInputProps<T> & React.RefAttributes<DOMElement>) => React.ReactElement | null;
\ No newline at end of file
|
|
|
||
| if (!result.success && !step.continueOnError) { | ||
| throw new Error(`Build step "${step.displayName}" failed: ${result.error?.message}`) | ||
| } |
There was a problem hiding this comment.
Duplicate/double-wrapped error handling in ExtensionInstance.build()
executeStep() already throws when a step fails and continueOnError is false:
throw new Error(`Build step "${step.displayName}" failed: ${stepError.message}`)But ExtensionInstance.build() then checks:
if (!result.success && !step.continueOnError) {
throw new Error(`Build step "${step.displayName}" failed: ${result.error?.message}`)
}That condition is effectively unreachable because executeStep() won’t return {success:false} unless continueOnError is true. This is dead logic and also risks producing a worse error message (e.g., undefined) if behavior changes later.
Impact:
- User impact: Confusing/duplicated error messaging during builds; harder debugging.
- Infra impact: No direct outage risk, but increases operational toil.
644b571 to
d9664fc
Compare
8b922b5 to
38a9028
Compare
| import {bundleThemeExtension, copyFilesForExtension} from '../../services/extensions/bundle.js' | ||
| import {ExtensionBuildOptions, bundleFunctionExtension} from '../../services/build/extension.js' | ||
| import {bundleThemeExtension} from '../../services/extensions/bundle.js' | ||
| import {BuildContext, executeStep} from '../../services/build/build-steps.js' |
There was a problem hiding this comment.
Import target for build steps points to non-existent module (runtime crash)
ExtensionInstance imports BuildContext/executeStep from ../../services/build/build-steps.js, but that file does not exist in the repo. The actual implementation is packages/app/src/cli/services/build/client-steps.ts, which exports executeStep and BuildContext. This will fail Node ESM module resolution at runtime, breaking any command path that loads extension-instance.ts (build, deploy, etc.).
| context.stepResults.set(step.id, result) | ||
|
|
||
| if (!result.success && !step.continueOnError) { | ||
| throw new Error(`Build step "${step.displayName}" failed: ${result.error?.message}`) |
There was a problem hiding this comment.
Step shape mismatch: executor expects name, configs/build loop use displayName
The build loop references step.displayName for error messages, while the executor (client-steps.ts) expects a ClientStep with name and logs using step.name. Updated step specs appear to use displayName rather than name, which can result in logs like Executing step: undefined and unreliable routing/error reporting. If TypeScript is strictly enforced, this should fail typechecking; otherwise it degrades observability and debugging.
38a9028 to
a5303fd
Compare
1fa9fa8 to
174ca57
Compare
a5303fd to
0945d47
Compare
174ca57 to
9964055
Compare
0945d47 to
c468483
Compare
9964055 to
d835caf
Compare
c468483 to
067c371
Compare
067c371 to
be84850
Compare
d835caf to
57a0790
Compare
be84850 to
dd1d204
Compare
57a0790 to
316c2ab
Compare
785afb4 to
a7efd5b
Compare
a7efd5b to
e90a1b3
Compare

WHY are these changes introduced?
Fixes #0000
WHAT is this pull request doing?
How to test your changes?
Post-release steps
Measuring impact
How do we know this change was effective? Please choose one:
Checklist